package com.lauor.smpedr.session.provider;

import com.lauor.smpedr.Configuration;
import com.lauor.smpedr.core.SqlGenerator;
import com.lauor.smpedr.core.executor.BaseExecutor;
import com.lauor.smpedr.core.executor.Executor;
import com.lauor.smpedr.core.executor.ExecutorProxy;
import com.lauor.smpedr.core.handler.provider.DefaultResultSetHandler;
import com.lauor.smpedr.core.handler.ResultSetHandler;
import com.lauor.smpedr.session.SqlSession;
import com.lauor.smpedr.session.SqlSessionFactory;
import com.lauor.smpedr.session.SqlSessionProxy;
import com.lauor.smpedr.transaction.Transaction;
import com.lauor.smpedr.transaction.TransactionIsolationLevel;

import javax.sql.DataSource;
import java.lang.reflect.Proxy;

/**
 * 默认SqlSession工厂
 */
public class DefaultSqlSessionFactory implements SqlSessionFactory {

    private Configuration configuration;

    private SqlGenerator sqlGenerator;

    private ResultSetHandler resultSetHandler;

    public DefaultSqlSessionFactory(Configuration configuration, SqlGenerator sqlGenerator, ResultSetHandler resultSetHandler) {
        this.configuration = configuration;
        this.sqlGenerator = sqlGenerator;
        this.resultSetHandler = resultSetHandler;
    }

    public DefaultSqlSessionFactory(Configuration configuration, SqlGenerator sqlGenerator) {
        this(configuration, sqlGenerator, new DefaultResultSetHandler(configuration));
    }

    @Override
    public SqlSession openSession() {
        return this.openSqlSession(null, false);
    }

    @Override
    public SqlSession openSession(boolean autoCommit) {
        return this.openSqlSession(null, autoCommit);
    }

    @Override
    public SqlSession openSession(TransactionIsolationLevel level) {
        return this.openSqlSession(level, false);
    }

    @Override
    public SqlSession openSession(TransactionIsolationLevel level, boolean autoCommit) {
        return this.openSqlSession(level, autoCommit);
    }

    protected SqlSession openSqlSession(TransactionIsolationLevel level, boolean autoCommit){
        DataSource dataSource = this.configuration.getDataSource();
        Transaction transaction = this.configuration.getTransactionFactory().newTransaction(dataSource, level, autoCommit);

        Executor executor = new BaseExecutor(transaction, this.resultSetHandler, this.configuration);
        //executor代理
        Executor executorProxy = (Executor) Proxy.newProxyInstance(Executor.class.getClassLoader(), new Class[]{Executor.class}, new ExecutorProxy(executor));

        SqlSession sqlSession = new DefaultSqlSession(this.configuration, this.sqlGenerator, executorProxy);
        //构建代理对象
        return (SqlSession) Proxy.newProxyInstance(SqlSession.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionProxy(sqlSession));
    }

    @Override
    public SqlGenerator getSqlGenerator() {
        return this.sqlGenerator;
    }
}
